package cn.bonoon.handler.impl;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.util.StringUtils;

import cn.bonoon.core.plugins.LoginRecordService;
import cn.bonoon.handler.RedirectToUserHome;
import cn.bonoon.kernel.security.LogonUser;
import cn.bonoon.kernel.util.RequestHelper;
import cn.bonoon.kernel.web.models.JsonResult;

public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {

	private final Log logger = LogFactory.getLog(this.getClass());
    
	@Autowired
	@Qualifier("httpSessionRequestCache")
	private RequestCache requestCache;
	
	@Autowired
	private LoginRecordService loginRecordSevice;
	
	private final RedirectToUserHome loginSuccessRedirect;
	
//	/**
//	 * <pre>
//	 * 在配置文件里注入进来即可
//	 * 可自定义登录成功后，需要自定义处理的一些方法
//	 * </pre>
//	 */
//	private List<OnLoginSuccess> handlers;

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    private String targetUrlParameter = "redirect-url";
    public AuthenticationSuccessHandlerImpl(String url){
    	this.loginSuccessRedirect = new SimpleLoginSuccessRedirect(url);
    }
    
    public AuthenticationSuccessHandlerImpl(RedirectToUserHome loginSuccessRedirect){
    	this.loginSuccessRedirect = loginSuccessRedirect;
    }
    
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
		LogonUser logonUser = (LogonUser) authentication.getPrincipal();
		try {
			String agent = RequestHelper.getAgent(request);
			String ip = RequestHelper.getIpAddress(request);
			String sessionId = request.getSession().getId();
			logonUser.getRuntime().loginSuccess(sessionId, ip);
			
			loginRecordSevice.login(logonUser, agent, ip, true, sessionId);
//			loginRecordSevice.login(logonUser, RequestHelper.getAgent(request), RequestHelper.getIpAddress(request), true, request.getSession().getId());
		} catch (Throwable err) {
			// 忽略所有异常情况
			err.printStackTrace();
			logger.error("写登录记录异常", err);
		}
		
//		try {
//			if (null != handlers && !handlers.isEmpty()) {
//				for (OnLoginSuccess handler : handlers) {
//					handler.onSuccess(request, response, authentication, logonUser);
//				}
//			}
//		} catch (Throwable err) {
//			err.printStackTrace();
//			logger.error("子系统或插件定义的处理异常", err);
//		}
		
		if(isAjax(request)){
			ObjectMapper objectMapper = new ObjectMapper();
			response.setHeader("Content-Type", "application/json;charset=UTF-8");
			JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), JsonEncoding.UTF8);
			try {
				// 成功为0
				objectMapper.writeValue(jsonGenerator, JsonResult.result());
			} catch (JsonProcessingException ex) {
				throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
			}
			
			return ;
		}

		SavedRequest savedRequest = requestCache.getRequest(request, response);
		if(null != savedRequest){
			requestCache.removeRequest(request, response);
			clearAuthenticationAttributes(request);
	
			// Use the DefaultSavedRequest URL
			String targetUrl = savedRequest.getRedirectUrl();
			logger.debug("Redirecting to DefaultSavedRequest Url: " + targetUrl);
			redirectStrategy.sendRedirect(request, response, targetUrl);
			
			return ;
		}
		
        String targetUrl = request.getParameter(targetUrlParameter);// = determineTargetUrl(request, response);
        if (!StringUtils.hasText(targetUrl)) {
        	targetUrl = loginSuccessRedirect.redirectUrl(request, response, logonUser);
        }
        
        if (response.isCommitted()) {
            logger.debug("Response has already been committed. Unable to redirect to " + targetUrl);
            return;
        }

        redirectStrategy.sendRedirect(request, response, targetUrl);
        clearAuthenticationAttributes(request);
	}
	
	private boolean isAjax(HttpServletRequest request){ return false; }

    /**
     * Removes temporary authentication-related data which may have been stored in the session
     * during the authentication process.
     */
    protected final void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);

        if (session == null) {
            return;
        }

        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }

    /**
     * Allows overriding of the behaviour when redirecting to a target URL.
     */
    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }

    protected RedirectStrategy getRedirectStrategy() {
        return redirectStrategy;
    }
    
//    public void setHandlers(List<OnLoginSuccess> handlers) {
//		this.handlers = handlers;
//	}
    
    public void setTargetUrlParameter(String targetUrlParameter) {
		this.targetUrlParameter = targetUrlParameter;
	}
}
